home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.0.14 / python / xpcom / server / policy.py < prev   
Encoding:
Python Source  |  2006-10-16  |  17.0 KB  |  382 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is Python XPCOM language bindings.
  15. #
  16. # The Initial Developer of the Original Code is
  17. # ActiveState Tool Corp.
  18. # Portions created by the Initial Developer are Copyright (C) 2001
  19. # the Initial Developer. All Rights Reserved.
  20. #
  21. # Contributor(s):
  22. #  Mark Hammond <mhammond@skippinet.com.au> (original author)
  23. #
  24. # Alternatively, the contents of this file may be used under the terms of
  25. # either the GNU General Public License Version 2 or later (the "GPL"), or
  26. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. # in which case the provisions of the GPL or the LGPL are applicable instead
  28. # of those above. If you wish to allow use of your version of this file only
  29. # under the terms of either the GPL or the LGPL, and not to allow others to
  30. # use your version of this file under the terms of the MPL, indicate your
  31. # decision by deleting the provisions above and replace them with the notice
  32. # and other provisions required by the GPL or the LGPL. If you do not delete
  33. # the provisions above, a recipient may use your version of this file under
  34. # the terms of any one of the MPL, the GPL or the LGPL.
  35. #
  36. # ***** END LICENSE BLOCK *****
  37.  
  38. import sys
  39. from xpcom import xpcom_consts, _xpcom, client, nsError, logger
  40. from xpcom import ServerException, COMException
  41. import xpcom
  42. import xpcom.server
  43. import operator
  44. import types
  45. import logging
  46.  
  47.  
  48. IID_nsISupports = _xpcom.IID_nsISupports
  49. IID_nsIVariant = _xpcom.IID_nsIVariant
  50. XPT_MD_IS_GETTER = xpcom_consts.XPT_MD_IS_GETTER
  51. XPT_MD_IS_SETTER = xpcom_consts.XPT_MD_IS_SETTER
  52.  
  53. VARIANT_INT_TYPES = xpcom_consts.VTYPE_INT8, xpcom_consts.VTYPE_INT16, xpcom_consts.VTYPE_INT32, \
  54.                     xpcom_consts.VTYPE_UINT8, xpcom_consts.VTYPE_UINT16, xpcom_consts.VTYPE_INT32
  55. VARIANT_LONG_TYPES = xpcom_consts.VTYPE_INT64, xpcom_consts.VTYPE_UINT64
  56. VARIANT_FLOAT_TYPES = xpcom_consts.VTYPE_FLOAT, xpcom_consts.VTYPE_DOUBLE
  57. VARIANT_STRING_TYPES = xpcom_consts.VTYPE_CHAR, xpcom_consts.VTYPE_CHAR_STR, xpcom_consts.VTYPE_STRING_SIZE_IS, \
  58.                        xpcom_consts.VTYPE_CSTRING
  59. VARIANT_UNICODE_TYPES = xpcom_consts.VTYPE_WCHAR, xpcom_consts.VTYPE_DOMSTRING, xpcom_consts.VTYPE_WSTRING_SIZE_IS, \
  60.                         xpcom_consts.VTYPE_ASTRING 
  61.  
  62. _supports_primitives_map_ = {} # Filled on first use.
  63.  
  64. _interface_sequence_types_ = types.TupleType, types.ListType
  65. _string_types_ = types.StringType, types.UnicodeType
  66. XPTI_GetInterfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager
  67.  
  68. def _GetNominatedInterfaces(obj):
  69.     ret = getattr(obj, "_com_interfaces_", None)
  70.     if ret is None: return None
  71.     # See if the user only gave one.
  72.     if type(ret) not in _interface_sequence_types_:
  73.         ret = [ret]
  74.     real_ret = []
  75.     # For each interface, walk to the root of the interface tree.
  76.     iim = XPTI_GetInterfaceInfoManager()
  77.     for interface in ret:
  78.         # Allow interface name or IID.
  79.         interface_info = None
  80.         if type(interface) in _string_types_:
  81.             try:
  82.                 interface_info = iim.GetInfoForName(interface)
  83.             except COMException:
  84.                 pass
  85.         if interface_info is None:
  86.             # Allow a real IID
  87.             interface_info = iim.GetInfoForIID(interface)
  88.         real_ret.append(interface_info.GetIID())
  89.         parent = interface_info.GetParent()
  90.         while parent is not None:
  91.             parent_iid = parent.GetIID()
  92.             if parent_iid == IID_nsISupports:
  93.                 break
  94.             real_ret.append(parent_iid)
  95.             parent = parent.GetParent()
  96.     return real_ret
  97.  
  98. ##
  99. ## ClassInfo support
  100. ##
  101. ## We cache class infos by class
  102. class_info_cache = {}
  103.  
  104. def GetClassInfoForObject(ob):
  105.     if xpcom.server.tracer_unwrap is not None:
  106.         ob = xpcom.server.tracer_unwrap(ob)
  107.     klass = ob.__class__
  108.     ci = class_info_cache.get(klass)
  109.     if ci is None:
  110.         ci = DefaultClassInfo(klass)
  111.         ci = xpcom.server.WrapObject(ci, _xpcom.IID_nsIClassInfo, bWrapClient = 0)
  112.         class_info_cache[klass] = ci
  113.     return ci
  114.  
  115. class DefaultClassInfo:
  116.     _com_interfaces_ = _xpcom.IID_nsIClassInfo
  117.     def __init__(self, klass):
  118.         self.klass = klass
  119.         self.contractID = getattr(klass, "_reg_contractid_", None)
  120.         self.classDescription = getattr(klass, "_reg_desc_", None)
  121.         self.classID = getattr(klass, "_reg_clsid_", None)
  122.         self.implementationLanguage = 3 # Python - avoid lookups just for this
  123.         self.flags = 0 # what to do here??
  124.         self.interfaces = None
  125.  
  126.     def get_classID(self):
  127.         if self.classID is None:
  128.             raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED, "Class '%r' has no class ID" % (self.klass,))
  129.         return self.classID
  130.  
  131.     def getInterfaces(self):
  132.         if self.interfaces is None:
  133.             self.interfaces = _GetNominatedInterfaces(self.klass)
  134.         return self.interfaces
  135.  
  136.     def getHelperForLanguage(self, language):
  137.         return None # Not sure what to do here.
  138.  
  139. class DefaultPolicy:
  140.     def __init__(self, instance, iid):
  141.         self._obj_ = instance
  142.         self._nominated_interfaces_ = ni = _GetNominatedInterfaces(instance)
  143.         self._iid_ = iid
  144.         if ni is None:
  145.             raise ValueError, "The object '%r' can not be used as a COM object" % (instance,)
  146.         # This is really only a check for the user - the same thing is
  147.         # done by the framework.
  148.         # XXXmarkh - this should probably die now we have better error
  149.         # reporting in the framework!
  150.         if __debug__:
  151.             if iid != IID_nsISupports and iid not in ni:
  152.                 # The object may delegate QI.
  153.                 delegate_qi = getattr(instance, "_query_interface_", None)
  154.                 # Perform the actual QI and throw away the result - the _real_
  155.                 # QI performed by the framework will set things right!
  156.                 if delegate_qi is None or not delegate_qi(iid):
  157.                     raise ServerException(nsError.NS_ERROR_NO_INTERFACE)
  158.         # Stuff for the magic interface conversion.
  159.         self._interface_info_ = None
  160.         self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index)
  161.  
  162.     def _QueryInterface_(self, com_object, iid):
  163.         # Framework allows us to return a single boolean integer,
  164.         # or a COM object.
  165.         if iid in self._nominated_interfaces_:
  166.             # We return the underlying object re-wrapped
  167.             # in a new gateway - which is desirable, as one gateway should only support
  168.             # one interface (this won't affect the users of this policy - we can have as many
  169.             # gateways as we like pointing to the same Python objects - the users never
  170.             # see what object the call came in from.
  171.             # NOTE: We could have simply returned the instance and let the framework
  172.             # do the auto-wrap for us - but this way we prevent a round-trip back into Python
  173.             # code just for the autowrap.
  174.             return xpcom.server.WrapObject(self._obj_, iid, bWrapClient = 0)
  175.  
  176.         # Always support nsIClassInfo 
  177.         if iid == _xpcom.IID_nsIClassInfo:
  178.             return GetClassInfoForObject(self._obj_)
  179.  
  180.         # See if the instance has a QI
  181.         # use lower-case "_query_interface_" as win32com does, and it doesn't really matter.
  182.         delegate = getattr(self._obj_, "_query_interface_", None)
  183.         if delegate is not None:
  184.             # The COM object itself doesn't get passed to the child
  185.             # (again, as win32com doesnt).  It is rarely needed
  186.             # (in win32com, we don't even pass it to the policy, although we have identified
  187.             # one place where we should - for marshalling - so I figured I may as well pass it
  188.             # to the policy layer here, but no all the way down to the object.
  189.             return delegate(iid)
  190.         # Finally see if we are being queried for one of the "nsISupports primitives"
  191.         if not _supports_primitives_map_:
  192.             iim = _xpcom.XPTI_GetInterfaceInfoManager()
  193.             for (iid_name, attr, cvt) in _supports_primitives_data_:
  194.                 special_iid = iim.GetInfoForName(iid_name).GetIID()
  195.                 _supports_primitives_map_[special_iid] = (attr, cvt)
  196.         attr, cvt = _supports_primitives_map_.get(iid, (None,None))
  197.         if attr is not None and hasattr(self._obj_, attr):
  198.             return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid, bWrapClient = 0)
  199.         # Out of clever things to try!
  200.         return None # We don't support this IID.
  201.  
  202.     def _MakeInterfaceParam_(self, interface, iid, method_index, mi, param_index):
  203.         # Wrap a "raw" interface object in a nice object.  The result of this
  204.         # function will be passed to one of the gateway methods.
  205.         if iid is None:
  206.             # look up the interface info - this will be true for all xpcom called interfaces.
  207.             if self._interface_info_ is None:
  208.                 import xpcom.xpt
  209.                 self._interface_info_ = xpcom.xpt.Interface( self._iid_ )
  210.             iid = self._interface_iid_map_.get( (method_index, param_index))
  211.             if iid is None:
  212.                 iid = self._interface_info_.GetIIDForParam(method_index, param_index)
  213.                 self._interface_iid_map_[(method_index, param_index)] = iid
  214.         # handle nsIVariant
  215.         if iid == IID_nsIVariant:
  216.             interface = interface.QueryInterface(iid)
  217.             dt = interface.dataType
  218.             if dt in VARIANT_INT_TYPES:
  219.                 return interface.getAsInt32()
  220.             if dt in VARIANT_LONG_TYPES:
  221.                 return interface.getAsInt64()
  222.             if dt in VARIANT_FLOAT_TYPES:
  223.                 return interface.getAsFloat()
  224.             if dt in VARIANT_STRING_TYPES:
  225.                 return interface.getAsStringWithSize()
  226.             if dt in VARIANT_UNICODE_TYPES:
  227.                 return interface.getAsWStringWithSize()
  228.             if dt == xpcom_consts.VTYPE_BOOL:
  229.                 return interface.getAsBool()
  230.             if dt == xpcom_consts.VTYPE_INTERFACE:
  231.                 return interface.getAsISupports()
  232.             if dt == xpcom_consts.VTYPE_INTERFACE_IS:
  233.                 return interface.getAsInterface()
  234.             if dt == xpcom_consts.VTYPE_EMPTY or dt == xpcom_consts.VTYPE_VOID:
  235.                 return None
  236.             if dt == xpcom_consts.VTYPE_ARRAY:
  237.                 return interface.getAsArray()
  238.             if dt == xpcom_consts.VTYPE_EMPTY_ARRAY:
  239.                 return []
  240.             if dt == xpcom_consts.VTYPE_ID:
  241.                 return interface.getAsID()
  242.             # all else fails...
  243.             logger.warning("Warning: nsIVariant type %d not supported - returning a string", dt)
  244.             try:
  245.                 return interface.getAsString()
  246.             except COMException:
  247.                 logger.exception("Error: failed to get Variant as a string - returning variant object")
  248.                 return interface
  249.             
  250.         return client.Component(interface, iid)
  251.     
  252.     def _CallMethod_(self, com_object, index, info, params):
  253.         #print "_CallMethod_", index, info, params
  254.         flags, name, param_descs, ret = info
  255.         assert ret[1][0] == xpcom_consts.TD_UINT32, "Expected an nsresult (%s)" % (ret,)
  256.         if XPT_MD_IS_GETTER(flags):
  257.             # Look for a function of that name
  258.             func = getattr(self._obj_, "get_" + name, None)
  259.             if func is None:
  260.                 assert len(param_descs)==1 and len(params)==0, "Can only handle a single [out] arg for a default getter"
  261.                 ret = getattr(self._obj_, name) # Let attribute error go here!
  262.             else:
  263.                 ret = func(*params)
  264.             return 0, ret
  265.         elif XPT_MD_IS_SETTER(flags):
  266.             # Look for a function of that name
  267.             func = getattr(self._obj_, "set_" + name, None)
  268.             if func is None:
  269.                 assert len(param_descs)==1 and len(params)==1, "Can only handle a single [in] arg for a default setter"
  270.                 setattr(self._obj_, name, params[0]) # Let attribute error go here!
  271.             else:
  272.                 func(*params)
  273.             return 0
  274.         else:
  275.             # A regular method.
  276.             func = getattr(self._obj_, name)
  277.             return 0, func(*params)
  278.  
  279.     def _doHandleException(self, func_name, exc_info):
  280.         exc_val = exc_info[1]
  281.         is_server_exception = isinstance(exc_val, ServerException)
  282.         if is_server_exception:
  283.             # When a component raised an explicit COM exception, it is
  284.             # considered 'normal' - however, we still write a debug log
  285.             # record to help track these otherwise silent exceptions.
  286.  
  287.             if sys.version_info < (2,4):
  288.                 # Note that Python 2.3 does not allow an explicit exc_info tuple
  289.                 # and passing 'True' will not work as there is no exception pending.
  290.                 # Trick things!
  291.                 if logger.isEnabledFor(logging.DEBUG):
  292.                     try:
  293.                         raise exc_info[0], exc_info[1], exc_info[2]
  294.                     except:
  295.                         logger.debug("'%s' raised COM Exception %s",
  296.                                  func_name, exc_val, exc_info = 1)
  297.             else:
  298.                 logger.debug("'%s' raised COM Exception %s",
  299.                              func_name, exc_val, exc_info=exc_info)
  300.  
  301.             return exc_val.errno
  302.         # Unhandled exception - always print a warning and the traceback.
  303.         # As above, trick the logging module to handle Python 2.3
  304.         if sys.version_info < (2,4):
  305.             try:
  306.                 raise exc_info[0], exc_info[1], exc_info[2]
  307.             except:
  308.                 logger.exception("Unhandled exception calling '%s'", func_name)
  309.         else:
  310.             logger.error("Unhandled exception calling '%s'", func_name,
  311.                          exc_info=exc_info)
  312.         return nsError.NS_ERROR_FAILURE
  313.  
  314.     # Called whenever an unhandled Python exception is detected as a result
  315.     # of _CallMethod_ - this exception may have been raised during the _CallMethod_
  316.     # invocation, or after its return, but when unpacking the results
  317.     # eg, type errors, such as a Python integer being used as a string "out" param.
  318.     def _CallMethodException_(self, com_object, index, info, params, exc_info):
  319.         # Later we may want to have some smart "am I debugging" flags?
  320.         # Or maybe just delegate to the actual object - it's probably got the best
  321.         # idea what to do with them!
  322.         flags, name, param_descs, ret = info
  323.         exc_typ, exc_val, exc_tb = exc_info
  324.         # use the xpt module to get a better repr for the method.
  325.         # But if we fail, ignore it!
  326.         try:
  327.             import xpcom.xpt
  328.             m = xpcom.xpt.Method(info, index, None)
  329.             func_repr = m.Describe().lstrip()
  330.         except COMException:
  331.             func_repr = "%s(%r)" % (name, param_descs)
  332.         except:
  333.             # any other errors are evil!?  Log it
  334.             self._doHandleException("<building method repr>", sys.exc_info())
  335.             # And fall through to logging the original error.
  336.         return self._doHandleException(func_repr, exc_info)
  337.  
  338.     # Called whenever a gateway fails due to anything other than _CallMethod_.
  339.     # Really only used for the component loader etc objects, so most
  340.     # users should never see exceptions triggered here.
  341.     def _GatewayException_(self, name, exc_info):
  342.         return self._doHandleException(name, exc_info)
  343.  
  344. _supports_primitives_data_ = [
  345.     ("nsISupportsCString", "__str__", str),
  346.     ("nsISupportsString", "__unicode__", unicode),
  347.     ("nsISupportsPRUint64", "__long__", long),
  348.     ("nsISupportsPRInt64", "__long__", long),
  349.     ("nsISupportsPRUint32", "__int__", int),
  350.     ("nsISupportsPRInt32", "__int__", int),
  351.     ("nsISupportsPRUint16", "__int__", int),
  352.     ("nsISupportsPRInt16", "__int__", int),
  353.     ("nsISupportsPRUint8", "__int__", int),
  354.     ("nsISupportsPRBool", "__nonzero__", operator.truth),
  355.     ("nsISupportsDouble", "__float__", float),
  356.     ("nsISupportsFloat", "__float__", float),
  357. ]
  358.  
  359. # Support for the nsISupports primitives:
  360. class SupportsPrimitive:
  361.     _com_interfaces_ = ["nsISupports"]
  362.     def __init__(self, iid, base_ob, attr_name, converter):
  363.         self.iid = iid
  364.         self.base_ob = base_ob
  365.         self.attr_name = attr_name
  366.         self.converter = converter
  367.     def _query_interface_(self, iid):
  368.         if iid == self.iid:
  369.             return 1
  370.         return None
  371.     def get_data(self):
  372.         method = getattr(self.base_ob, self.attr_name)
  373.         val = method()
  374.         return self.converter(val)
  375.     def set_data(self, val):
  376.         raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
  377.     def toString(self):
  378.         return str(self.get_data())
  379.  
  380. def _shutdown():
  381.     class_info_cache.clear()
  382.